#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>

#define MAX_SIZE 255  //at24c02的最大值
#define EEPROM_PAGE  16 //页字节大小
//咱们是4.6的内核 所以是.probe 而不是.prober nwe
static int major = -1; //主设备号 由内核分配
static struct class  *myat24_class = NULL;
static struct i2c_client *myat24_client = NULL;
static unsigned char eeprom_buff[255];
// 这里看看eeprom打开需要怎么做
static ssize_t myat24_open(struct inode *node, struct file *file)
{
    //i2c_smbus_write_byte_data(const struct i2c_client *client, u8 command, u8 value)
    //delay
    //i2c_smbus_write_byte_data
    //delay
    printk("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
    return 0;
}
static ssize_t myat24_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
    int err;
    if(*offset + size > MAX_SIZE)
        size = MAX_SIZE - *offset;
    i2c_smbus_read_i2c_block_data(myat24_client, *offset,size,eeprom_buff);
    //copy_to_user(void *to, const void *from, unsigned long n)
    err = copy_to_user(buf,eeprom_buff,size);
	if(err != 0)return -1;
	*offset += size;
	return size;
}

static ssize_t myat24_write(struct file *file, const char __user *buf, size_t size, loff_t *seek)
{
    size_t write_ok_cnt=0;
	unsigned long err;
	err = copy_from_user(eeprom_buff,buf,size);
	if(err != 0) return -1;
	//判断位置是否超出范围
	if(*seek + size > MAX_SIZE)
	{
		size = MAX_SIZE - *seek;
	}
	
	int write_byte=0;
	u8 *write_p=eeprom_buff;
	while(1)
	{
		if(size > EEPROM_PAGE)
		{
			write_byte = EEPROM_PAGE;
			size -= EEPROM_PAGE;
		}
		else
		{
			write_byte = size;
		}
		
		//写数据
		i2c_smbus_write_i2c_block_data(myat24_client,*seek,write_byte,write_p);
		*seek += write_byte;
		write_p += write_byte;
		write_ok_cnt += write_byte;  //记录写成功的字节数
		//等待写完成
		msleep(10);
		if(write_byte == size)break; //写完毕
	}
	return write_ok_cnt;
}
static loff_t myat24_llseek(struct file *filp, loff_t offset, int whence)
{
	loff_t newpos = 0;
	switch(whence)
	{
		case SEEK_SET:
			newpos = offset;
			break;
		case SEEK_CUR:
			newpos = filp->f_pos + offset;
			break;
		case SEEK_END:
			if(MAX_SIZE+offset>=MAX_SIZE)
			{
				newpos=MAX_SIZE;
			}
			else
			{
				newpos = MAX_SIZE + offset;
			}
			break;
		default:
			return -EINVAL;//无效的参数
	}
	filp->f_pos = newpos;
	return newpos;
}
static int myat24_release(struct inode *inode, struct file *file)
{
	printk("tiny4412_release-->ok\n");
	return 0;
}
static struct file_operations myat24 = {
    .owner = THIS_MODULE,
    .open = myat24_open,
    .read = myat24_read,
    .write = myat24_write,
    .release = myat24_release,
	.llseek = myat24_llseek
};
static const struct of_device_id at24_of_match[] = {
	{ .compatible = "lcs,my24c02",		.data = NULL },//没有芯片相关的私有数据
	{ /* END OF LIST */ },//这个一定得有
};
static const struct i2c_device_id at24_ids[] = {
	{ "my24c02",	(kernel_ulong_t)NULL },
	{ /* END OF LIST */ }
};
//probe确实会被多次调用在for_each_dev函数中
static int my_at24_probe(struct i2c_client *client, const struct i2c_device_id *client_id)
{
    /*register _chardev*/
    myat24_client = client; //指定的client 假设就一个的情况下吧
    major = register_chrdev(0,"myat24CXX",&myat24);
    /*创建类*/
    if(!myat24_class)
    {
        myat24_class = class_create(THIS_MODULE,"myat24_class");
        if(!myat24_class)
            printk("%s %s error class create\r\n",__FILE__,__FUNCTION__);
        
    }
    /*创建一个设备*/
    //假设我创建两个会发生什么
    device_create(myat24_class,NULL,MKDEV(major, 0),NULL,"myat24c02");
    device_create(myat24_class,NULL,MKDEV(major, 257),NULL,"myat24c0201");
    return 0;

}
static int my_at24_remove(struct i2c_client *client)
{
    /*unregister _chardev*/
    device_destroy(myat24_class,MKDEV(major, 0));
    device_destroy(myat24_class,MKDEV(major, 1));
    class_destroy(myat24_class);
    unregister_chrdev(major, "myat24");
    return 0;
}

static struct i2c_driver at24_driver = {
	.driver = {
		.name = "myat24cxx",
		.of_match_table = at24_of_match,
	},
	.probe = my_at24_probe, //imx6ull可能还是.probe 看内核版本
	.remove = my_at24_remove,
	.id_table = at24_ids, //不管来自设备树还是手工创建
};


static int __init my_at24_init(void)
{
    printk("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
    return i2c_add_driver(&at24_driver);
}
module_init(my_at24_init);

static void __exit my_at24_exit(void)
{
    i2c_del_driver(&at24_driver);
}

module_exit(my_at24_exit);

MODULE_DESCRIPTION("Driver I2C EEPROMs");
MODULE_AUTHOR("LCS");
MODULE_LICENSE("GPL");